package com.example.origin.flowable.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.example.origin.flowable.utils.JsonPrintUtil;
import org.apache.commons.io.IOUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;

@RestController
@RequestMapping("expression")
public class ExpressionController {

    @Autowired
    private ProcessEngine processEngine;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    private static final String BPMN_EXPRESSION="bpmn/表达式.bpmn20.xml";

    // 方法执行成功后会在这三张表中记录相关的部署信息
    // act_ge_bytearray:记录流程定义的资源信息，xm和流程图的图片信息
    // act_re_deployment:流程部署表，记录这次的部署行为
    // act_re_procdef::流程定义表，记录这次部署动作对应的流程定义信息
    @GetMapping("deployFlow")
    public String deployFlow() {
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource(BPMN_EXPRESSION).name("表达式流程图").deploy();//部署的方法
        Map<String, Object> stringObjectMap = BeanUtil.beanToMap(deploy);
        stringObjectMap.remove("resources");
        return JSONUtil.toJsonPrettyStr(stringObjectMap);
    }



    @GetMapping("deployFlow2")
    public String deployFlow2() {
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource(BPMN_EXPRESSION).name("表达式流程图").deploy();//部署的方法
        return jsonStr(deploy);
    }
    private String jsonStr(Object deploy){
        return JsonPrintUtil.jsonStr(deploy);
    }

    private <T> String jsonStr(List<T> list){
        return JsonPrintUtil.jsonStr(list);
    }



    @GetMapping("findDeployFlows")
    public String findDeployFlows() {
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().orderByProcessDefinitionId().desc().list();
        return jsonStr(list);
    }


    // act_re_procdef.id
    // act_re_procdef.key

    // 这时我们可以在act-ru-task表中看到对应的记录。act-ru-task记录的都是当前待办的记录信息

    //还有一个要注意的：每启动一个流程实例那么就会在act-hi-procinst表中维护一条记录。然后在
    //act-ru_execution会记录流程的分支
    //流程定义和流程实例的关系：
    //·流程定义：Java中的淡
    //·流程实例：Java中的对象
    @GetMapping("startFlow")
    public String startFlow(@RequestParam String processDefId) {
        //在流程定义表中动态维护
        //String processId = "5a5fc577-151f-11ef-afc6-005056c00008";
        //String processKey = "FirstFlow";//我们创建流程图的时候自定义的。注意保证睢一
        //1.根据流程定义工D启动流程实例
         ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefId);
        //2.根据流程定义Key启动流程实例
        //ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processKey);
        return jsonStr(processInstance);
    }
    // act-ru-task
    @GetMapping("findUndoTasks")
    public String findUndoTasks(@RequestParam String processId) {
        //act_ru_task
        List<Task> list = taskService.createTaskQuery().processInstanceId(processId)
                .list();
        return jsonStr(list);

    }

    // act-ru-task
    @GetMapping("completeTask")
    public String completeTask(@RequestParam String taskId) {
        Map<String,Object> map = new HashMap<>();
        map.put("user","jerry");
        //完成任务的中批。根解任务的ID
        taskService.complete(taskId,map);
        return "";
    }

    @GetMapping("findHistorys")
    public String findHistorys(@RequestParam String processId) {
        List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(processId).orderByProcessInstanceEndTime().desc().list();
        return jsonStr(list);
    }




    /**
     * 流程的挂起和激活
     *
     */

    // 已经挂起的流程，不能启动，但是不影响已经启动的
    @GetMapping("suspendedActivity")
    public String suspendedActivity(@RequestParam String processDefId) {
        //做流程的挂起和激活操作->针对的流程定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().
                processDefinitionId(processDefId).singleResult();
        //获取当前的流程定义的状态
        boolean suspended = processDefinition.isSuspended();//获取是否挂起
        if (suspended) {
            //表示挂起--》需要激活流程
            System.out.println("激活流程");
            repositoryService.activateProcessDefinitionById(processDefId);
        } else {
            //表示激活-~》挂起流程
            System.out.println("挂起流程");
            repositoryService.suspendProcessDefinitionById(processDefId);
        }
        return  "";
    }
    /**
     * 流程实例的挂起
     *
     */
    @GetMapping("suspendInstance")
    public String suspendInstance(@RequestParam String processId) {
        //排起流程实例
        runtimeService.suspendProcessInstanceById(processId);
        //激活流程实例
        //runtimeService.activateProcessInstanceById("a7ae5680-7ba3-11ee-809a-c03c59ad2248");
        return "";
    }

    @Autowired
    private HistoryService historyService;

    @GetMapping(value = "/getProcessDiagram")
    public void getProcessDiagram(@RequestParam String processId,HttpServletResponse httpServletResponse) {

//        // 根据任务 ID 获取流程实例 ID
//        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
//        String processInstanceId = task.getProcessInstanceId();

        // 根据流程实例获取流程图
        // 流程定义 ID
        String processDefinitionId;

        // 查看完成的进程中是否存在此进程
        long count = historyService.createHistoricProcessInstanceQuery().finished().processInstanceId(processId).count();
        if (count > 0) {
            // 如果流程已经结束，则得到结束节点
            HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult();

            processDefinitionId = pi.getProcessDefinitionId();
        } else {// 如果流程没有结束，则取当前活动节点
            // 根据流程实例ID获得当前处于活动状态的ActivityId合集
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
            processDefinitionId = pi.getProcessDefinitionId();
        }
        List<String> highLightedActivitis = new ArrayList<>();

        // 获得活动的节点
        List<HistoricActivityInstance> highLightedActivitList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list();

        for (HistoricActivityInstance tempActivity : highLightedActivitList) {
            String activityId = tempActivity.getActivityId();
            highLightedActivitis.add(activityId);
        }

        List<String> flows = new ArrayList<>();
        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        ProcessEngineConfiguration processEngineConfig = processEngine.getProcessEngineConfiguration();

        ProcessDiagramGenerator diagramGenerator = processEngineConfig.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "bmp", highLightedActivitis, flows, processEngineConfig.getActivityFontName(),
                processEngineConfig.getLabelFontName(), processEngineConfig.getAnnotationFontName(), processEngineConfig.getClassLoader(), 1.0, true);

        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth;
        try {
            out = httpServletResponse.getOutputStream();
            while ((legth = in.read(buf)) != -1) {
                out.write(buf, 0, legth);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(out);
            IOUtils.closeQuietly(in);
        }
    }





}
